package com.sinvo.oa.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sinvo.oa.entity.model.process.Process;
import com.sinvo.oa.entity.model.process.ProcessRecord;
import com.sinvo.oa.entity.model.process.ProcessTemplate;
import com.sinvo.oa.entity.model.system.SysUser;
import com.sinvo.oa.entity.vo.process.ApprovalVo;
import com.sinvo.oa.entity.vo.process.ProcessFormVo;
import com.sinvo.oa.entity.vo.process.ProcessQueryVo;
import com.sinvo.oa.entity.vo.process.ProcessVo;
import com.sinvo.oa.mapper.ProcessMapper;
import com.sinvo.oa.service.*;
import com.sinvo.oa.util.LoginUserInfoUtils;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * @Description ProcessService实现类
 */
@Service
public class ProcessServiceImpl extends ServiceImpl<ProcessMapper, Process> implements ProcessService {

    @Autowired
    private ProcessMapper processMapper;

    @Autowired
    private ProcessTemplateService processTemplateService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private ProcessRecordService processRecordService;

    @Autowired
    private WechatMessageService wechatMessageService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;


    @Override
    public Page<ProcessVo> selectPage(Page<ProcessVo> page, ProcessQueryVo processQueryVo) {
        Page<ProcessVo> pageModel = processMapper.queryProcessByPage(page, processQueryVo);
        return pageModel;
    }

    @Override
    public void deployByZip(String deployPath) {
        //获取输入流
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(deployPath);
        ZipInputStream zis = new ZipInputStream(is);
        //部署activiti
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zis)
                .deploy();
        System.out.println("部署id:"+deployment.getId());
        System.out.println("部署名:"+deployment.getName());
    }

    @Transactional
    @Override
    public void startUp(ProcessFormVo processFormVo) {
        //根据当前用户获取信息
        SysUser sysUser = sysUserService.getById(LoginUserInfoUtils.getUserId());
        //根据模板id查询信息
        ProcessTemplate processTemplate = processTemplateService.getById(processFormVo.getProcessTemplateId());
        //保存信息到process表
        Process process = new Process();
        //拷贝值
        BeanUtils.copyProperties(processFormVo, process);
        //补全数据 审批中status为1
        process.setStatus(1);
        String processCode = System.currentTimeMillis() + "";
        process.setProcessCode(processCode);
        process.setUserId(LoginUserInfoUtils.getUserId());
        process.setTitle(sysUser.getName() + "发起" + processTemplate.getName() + "申请");
        this.save(process);
        //启动流程
        //流程定义id
        String processDefinitionKey = processTemplate.getProcessDefinitionKey();
        //业务id
        String businessKey = String.valueOf(process.getId());
        //流程参数
        String formValues = processFormVo.getFormValues();
        JSONObject jsonObject = JSON.parseObject(formValues);
        JSONObject formData = jsonObject.getJSONObject("formData");
        //遍历formData 得到map
        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : formData.entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }
        Map<String, Object> variables = new HashMap<>();
        variables.put("data", map);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        //查询接下来的审批人
        List<Task> list = this.getTaskList(processInstance.getId());
        List<String> nameList = new ArrayList<>();
        for (Task task : list) {
            String assignee = task.getAssignee();
            SysUser user = sysUserService.findUserByUserName(assignee);
            String name = user.getName();
            nameList.add(name);
            //推送消息
            wechatMessageService.pushPendingMessage(process.getId(),user.getId(),task.getId());
        }
        process.setProcessInstanceId(processInstance.getId());
        process.setDescription("等待" + StringUtils.join(nameList.toArray(), "，") + "审批");
        this.updateById(process);
        //记录审批信息
        processRecordService.record(process.getId(), 1, "发起审批");
    }

    /**
     * 获取审批实例的审批人
     *
     * @param id instanceId
     * @return List<Task>
     */
    private List<Task> getTaskList(String id) {
        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(id)
                .list();
        return taskList;
    }

    @Override
    public Page<ProcessVo> getPending(Page<Process> page) {
        //查询条件 当前的登录用户
        TaskQuery query = taskService.createTaskQuery()
                .taskAssignee(LoginUserInfoUtils.getUsername())
                .orderByTaskCreateTime()
                .desc();
        //查询登录用户的待办审批
        int begin = (int) ((page.getCurrent() - 1) * page.getSize());
        int size = (int) page.getSize();
        List<Task> taskList = query.listPage(begin, size);
        long total = query.count();
        //封装到voList
        List<ProcessVo> processVoList = new ArrayList<>();
        for (Task task : taskList) {
            //获取流程实例id
            String processInstanceId = task.getProcessInstanceId();
            //根据实例id获取实例对象
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();
            //获取业务key也就是processId
            String businessKey = processInstance.getBusinessKey();
            if (businessKey == null) {
                continue;
            }
            //根据业务key获取process
            Process process = this.getById(businessKey);
            //封装为processVO
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process, processVo);
            processVo.setTaskId(task.getId());
            processVoList.add(processVo);
        }
        //封装返回page
        Page<ProcessVo> processVoPage = new Page<>(page.getCurrent(), page.getSize(), total);
        processVoPage.setRecords(processVoList);
        return processVoPage;
    }

    @Override
    public Map<String, Object> showDetail(Long id) {
        //根据流程id查询流程
        Process process = this.getById(id);
        //根据流程id获取流程记录
        LambdaQueryWrapper<ProcessRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcessRecord::getProcessId, id);
        List<ProcessRecord> processRecordList = processRecordService.list(queryWrapper);
        //根据模板id查询模板数据
        ProcessTemplate processTemplate = processTemplateService.getById(process.getProcessTemplateId());
        Boolean isApprove = false;
        List<Task> taskList = getTaskList(process.getProcessInstanceId());
        for (Task task : taskList) {
            String username = LoginUserInfoUtils.getUsername();
            if (task.getAssignee().contains(username)) {
                isApprove = true;
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("process", process);
        map.put("processRecordList", processRecordList);
        map.put("processTemplate", processTemplate);
        map.put("isApprove", isApprove);
        return map;
    }

    @Override
    public void approveProcess(ApprovalVo approvalVo) {
        //根据taskId获取流程变量
        String taskId = approvalVo.getTaskId();
        Map<String, Object> variables = taskService.getVariables(taskId);
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
        //1为通过 -1驳回
        if (approvalVo.getStatus() == 1) {
            taskService.complete(taskId);
        } else {
            this.endTask(taskId);
        }
        //更新记录
        String description = approvalVo.getStatus() == 1 ? "已通过" : "已驳回";
        processRecordService.record(approvalVo.getProcessId(), approvalVo.getStatus(), description);
        //查询下一个审批人
        Process process = this.getById(approvalVo.getProcessId());
        List<Task> taskList = getTaskList(process.getProcessInstanceId());
        if (!CollectionUtils.isEmpty(taskList)) {
            List<String> assignList = new ArrayList<>();
            for (Task task : taskList) {
                String assignee = task.getAssignee();
                SysUser user = sysUserService.findUserByUserName(assignee);
                String name = user.getName();
                assignList.add(name);
            }
            //更新流程信息
            process.setDescription("等待" + StringUtils.join(assignList.toArray(), ",") + "审批");
            process.setStatus(1);
        } else {
            if (approvalVo.getStatus() == 1) {
                process.setDescription("审批完成(已通过)");
                process.setStatus(2);
            } else {
                process.setDescription("审批完成(已驳回)");
                process.setStatus(-1);
            }
        }
        this.updateById(process);
    }

    /**
     * 结束任务
     *
     * @param taskId
     */
    private void endTask(String taskId) {
        //根据taskId获取任务对象
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        //获取流程定义模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        //获取结束节点
        List<EndEvent> endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        if (CollectionUtils.isEmpty(endEventList)) {
            return;
        }
        //获取结束节点
        FlowNode endFlowNode = endEventList.get(0);
        //获取当前节点
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
        //临时保存当前活动的原始方向
        List originalSequenceFlowList = new ArrayList<>();
        originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
        //清理活动方向
        currentFlowNode.getOutgoingFlows().clear();
        //创建新流向
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId("newSequenceFlow");
        sequenceFlow.setSourceFlowElement(currentFlowNode);
        sequenceFlow.setTargetFlowElement(endFlowNode);
        //当前节点指向新方向
        List sequenceFlowList = new ArrayList();
        sequenceFlowList.add(sequenceFlow);
        currentFlowNode.setOutgoingFlows(sequenceFlowList);
        //完成任务
        taskService.complete(taskId);
    }

    @Override
    public Page<ProcessVo> getProcessed(Page<Process> page) {
        //封装查询条件
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(LoginUserInfoUtils.getUsername())
                .finished()
                .orderByTaskCreateTime()
                .desc();
        int begin = (int) ((page.getCurrent() - 1) * page.getSize());
        int size = (int) page.getSize();
        List<HistoricTaskInstance> list = query.listPage(begin, size);
        long total = query.count();
        //遍历list封装成List<ProcessVo>
        List<ProcessVo> processVoList = new ArrayList<>();
        for (HistoricTaskInstance instance : list) {
            String processInstanceId = instance.getProcessInstanceId();
            //根据实例id获取process
            LambdaQueryWrapper<Process> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Process::getProcessInstanceId, processInstanceId);
            Process process = this.getOne(queryWrapper);
            if (process == null) continue;
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process, processVo);
            processVoList.add(processVo);
        }
        System.out.println("已处理："+processVoList);
        //封装page
        Page<ProcessVo> pageModel = new Page<>(page.getCurrent(), page.getSize(), total);
        pageModel.setRecords(processVoList);
        return pageModel;
    }

    @Override
    public Page<ProcessVo> findStarted(Page<ProcessVo> page) {
        ProcessQueryVo processQueryVo = new ProcessQueryVo();
        processQueryVo.setUserId(LoginUserInfoUtils.getUserId());
        Page<ProcessVo> pageModel = processMapper.queryProcessByPage(page, processQueryVo);
        return pageModel;
    }
}
